import type { HitRecord } from "./hitUtil"
import { Ray } from "./rayUtil"
import { Vec3 } from "./vectorUtil"

/**
 * 物体材质
 */
export interface Material {
  /** 是漫反射 */
  isDiffuce: boolean
  /** 散射 */
  scatter: (rayIn: Ray, hit: HitRecord) => [Ray, Attenuation]
}

/** 衰减 */
export type Attenuation = Vec3

/** 金属材质，镜面反射 */
export class Metal implements Material {
  /** 反射颜色 */
  albedo: Vec3
  /** 不光滑程度 */
  fuzz: number
  /** 是漫反射 */
  isDiffuce: boolean = false

  constructor(albedo: Vec3 | number, fuzz: number = 0) {
    this.albedo = new Vec3(0, 0, 0).add(albedo)
    this.fuzz = fuzz
  }

  scatter(rayIn: Ray, hit: HitRecord): [Ray, Attenuation] {
    // 获得反射光线
    const ray = rayIn.reflect(hit)
    // 反射方向增加随机扰动
    if (this.fuzz !== 0) {
      ray.direction = ray.direction.add(randomInUnitSphere().mul(this.fuzz))
    }
    // 直接返回反射光线，衰减率以反射颜色定义是合理的，叠加白光到黑色
    return [ray, this.albedo]
  }
}

/**
 * 漫反射材质
 */
export default class Lambertian implements Material {
  /** 反射颜色 */
  albedo: Vec3
  /** 是漫反射 */
  isDiffuce: boolean = true

  constructor(albedo: Vec3 | number) {
    this.albedo = new Vec3(0, 0, 0).add(albedo)
  }

  scatter(_rayIn: Ray, hit: HitRecord): [Ray, Attenuation] {
    // 新建一个光线，以交互点为基础，法向量随机扰动
    const ray = new Ray(hit.point, hit.normal.add(randomInUnitSphere().mul(Math.random() * 10)))
    // const ray = new Ray(hit.point, hit.normal)
    return [ray, this.albedo]
  }
}


/**
 * 随机单位球向量
 * @returns 
 */
export function randomInUnitSphere() {
  let p: Vec3
  do {
    // 生成随机向量
    // 扩展长度2倍
    // 与参考向量相减
    p = new Vec3(Math.random(), Math.random(), Math.random())
      .mul(2.0)
      .sub(new Vec3(1, 1, 1))
    // 长度大于1为合法向量
  } while (p.squaredLength() > 1)

  return p
}